import datetime
import pymongo
import Core.MongoDB as MongoDB
import Core.Gadget as Gadget
import Core.Algorithm as Algo
import Core.IO as IO
import Core.DataSeries as DataSeries
import math
import copy
from Factors.General import *
from Factors.Price import *
import copy
import numpy as np

database = MongoDB.MongoDB("10.13.38.41", "27017")
'''
period = ANNULIZED_FACTOR
sqrtPeriod = math.sqrt(period)
'''
datetime1 = datetime.datetime(2005, 1, 1)
datetime1 = Gadget.ToUTCDateTime(datetime1)
datetime2 = datetime.datetime(2018, 10, 1)
datetime2 = Gadget.ToUTCDateTime(datetime2)
instruments = database.find("Instruments", "Stock", datetime1,datetime2)

def SimpleProfitabilityCallback(dfFundamental, factorName, fields, params):
    #
    type = "_" + params["Type"]
    numerator = params["Numerator"]
    denominator = params["Denominator"]
    #
    if type == "LYR":
        dfFundamental[factorName] = dfFundamental[numerator + type] / dfFundamental[denominator + type]
    else:
        dfFundamental[factorName] = dfFundamental[numerator + type] / dfFundamental[denominator]

def CalcProfitabilityFactor(database,instruments,datetime1,datetime2,update=False):

    for i in range(2):
        if i == 0:
            type = "LYR"
        else:
            type = "TTM"

        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="CurrentRatio" + type,
                              fields=["CurrentAsset", "CurrentLiab"],
                              quarterlyFields=[],
                              callback=SimpleProfitabilityCallback,
                              params={"Numerator": "CurrentAsset", "Denominator": "CurrentLiab", "Type": type})

        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="ReceivablesTurnover" + type,
                              fields=["Receivable"],
                              quarterlyFields=["Sales"],
                              callback=SimpleProfitabilityCallback,
                              params={"Numerator": "Sales", "Denominator": "Receivable", "Type": type})

CalcProfitabilityFactor(database,instruments,datetime1,datetime2,update=False)
'''
        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="ROE" + type,
                              fields=["TotalEquity"],
                              quarterlyFields=["OperatingProfit1"],
                              callback=SimpleProfitabilityCallback,
                              params={"Numerator": "OperatingProfit1", "Denominator": "TotalEquity", "Type": type})

        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="FCFToAsset" + type,
                              fields=["TotalAsset"],
                              quarterlyFields=["FreeCashFlow"],
                              callback=SimpleProfitabilityCallback,
                              params={"Numerator": "FreeCashFlow", "Denominator": "TotalAsset", "Type": type})

        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="GreenblattROC" + type,
                              fields=["WorkingCapital","CashEquivalents","PPE"],
                              quarterlyFields=["EBIT"],
                              callback=GreenblattROCCallback,
                              params={"Type": type})

        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="GrossProfitOnAsset" + type,
                              fields=["TotalAsset"],
                              quarterlyFields=["Sales","GrossProfit"],
                              callback=GrossProfitOnAssetCallback,
                              params={"Type": type})

        CalcFundamentalFactor(database, instruments, datetime1, datetime2,
                              factorName="GrossProfitMargin" + type,
                              fields=[],
                              quarterlyFields=["Sales","GrossProfit"],
                              callback=GrossProfitMarginCallback,
                              params={"Type": type})
'''
'''
datetiem1 = datetime.datetime(2013, 1, 1)
datetiem1 = Gadget.ToUTCDateTime(datetiem1)
datetiem2 = datetime.datetime(2017, 5, 1)
datetiem2 = Gadget.ToUTCDateTime(datetiem2)
dfBars = IO.LoadBarsAsDataFrame(database, symbol="000001.SZ",
                                    datetime1=datetiem1, datetime2=datetiem2,
                                    fields=["BClose"])
rangeBegin = dfBars.loc[0, "DateTime"]
rangeEnd = dfBars.loc[len(dfBars) - 1, "DateTime"]
dfBenchmark = IO.LoadBarsAsDataFrame(database, symbol="000001.SH",
                                         datetime1=datetiem1, datetime2=datetiem2,
                                         fields=["Close"], databaseName="Index")
dfCombine = pd.merge(dfBenchmark, dfBars, on='DateTime', how='outer')
dfCombine.fillna(method='pad', inplace=True)
factorName = "DailyReturn"
dfCombine[factorName] = dfCombine["BClose"] / dfCombine["BClose"].shift(1) - 1
factorName2 = "DailyLogReturn"
dfCombine[factorName2] = np.log(dfCombine["BClose"] / dfCombine["BClose"].shift(1))
dfCombine['AnnualVolatility'] = dfCombine['DailyReturn'].rolling(245).std()*np.sqrt(245)
print (dfCombine)
'''

'''
for instrument in instruments:
    symbol = instrument["Symbol"]
    print (symbol)

    dfCombine = CalcReturnCallback(database, symbol, datetiem1 = datetime1, datetiem2 = datetime2, factorName = 'DailyReturn')
    dfCombine = dfCombine.dropna()
    length = len(dfCombine)
    # print(dfStock.head())
    if len(dfCombine) == 0:
        print("No Return Factor for" + symbol)
        continue
    # ---新股，数据不足的情况---
    if len(dfCombine) < period:
        print("Not Enough Data to Calc " + symbol)
        continue

    annualvolDataSeries = DataSeries.DataSeries(symbol + "_AnnualVolatility_Factor")

    for i in range(period - 1, len(dfCombine)):
        # ---准备数据---
        stdDateTime = dfCombine.at[i, "StdDateTime"]
        #stdDateTime = stdDateTime.tz_localize("Asia/Shanghai")

        slice = dfCombine[i - (period - 1):i + 1]
        DailyReturn = slice["DailyReturn"].std()*sqrtPeriod

        annualvolDataSeries.Add(GenarateDocument(symbol, stdDateTime, DailyReturn))
        pass
    database.saveDataSeries(annualvolDataSeries)
    pass
'''
'''
def CalcReturnCallback(database, symbol, datetiem1, datetiem2, factorName):

    #
    dfBars = IO.LoadBarsAsDataFrame(database, symbol=symbol,
                                    datetime1=datetiem1, datetime2=datetiem2,
                                    fields=["BClose"])

    # Might be Index
    if len(dfBars) == 0:
        dfBars = IO.LoadBarsAsDataFrame(database, symbol=symbol,
                                    datetime1=datetiem1, datetime2=datetiem2,
                                    fields=["Close"],databaseName="Index")
        dfBars.rename(columns={'Close': "BClose"}, inplace=True)

    # neither Stock or Index
    if len(dfBars) == 0:
        return pd.DataFrame()

    #
    #print(dfBars.head())
    rangeBegin = dfBars.loc[0, "StdDateTime"]
    rangeEnd = dfBars.loc[len(dfBars) - 1, "StdDateTime"]
    #

    dfBenchmark = IO.LoadBarsAsDataFrame(database, symbol="000001.SH",
                                         datetime1=rangeBegin, datetime2=rangeEnd,
                                         fields=["Close"], databaseName="Index")

    dfCombine = pd.merge(dfBenchmark, dfBars, on='StdDateTime', how='outer')
    #
    dfCombine.fillna(method='pad', inplace=True)
    #
    if factorName == "DailyReturn":
        dfCombine[factorName] = dfCombine["BClose"] / dfCombine["BClose"].shift(1) - 1
    elif factorName == "DailyLogReturn":
        dfCombine[factorName] = np.log(dfCombine["BClose"] / dfCombine["BClose"].shift(1))

    return dfCombine
'''
